#pragma once

#include <efi/device_path.hpp>
#include <efi/network.hpp>

#define EFI_DRIVER_BINDING_PROTOCOL_GUID                                       \
  {                                                                            \
    0x18a031ab, 0xb443, 0x4d1a, {                                              \
      0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71                           \
    }                                                                          \
  }

#define EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL_GUID                             \
  {                                                                            \
    0x6b30c738, 0xa391, 0x11d4, {                                              \
      0x9a, 0x3b, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d                           \
    }                                                                          \
  }

#define EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL_GUID                         \
  {                                                                            \
    0x3bc1b285, 0x8a15, 0x4a82, {                                              \
      0xaa, 0xbf, 0x4d, 0x7d, 0x13, 0xfb, 0x32, 0x65                           \
    }                                                                          \
  }

#define EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID                                   \
  {                                                                            \
    0x4d330321, 0x025f, 0x4aac, {                                              \
      0x90, 0xd8, 0x5e, 0xd9, 0x00, 0x17, 0x3b, 0x63                           \
    }                                                                          \
  }

#define EFI_COMPONENT_NAME2_PROTOCOL_GUID                                      \
  {                                                                            \
    0x6a7a5cff, 0xe8d9, 0x4f70, {                                              \
      0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14                           \
    }                                                                          \
  }

#define EFI_PLATFORM_TO_DRIVER_CONFIGURATION_PROTOCOL_GUID                     \
  {                                                                            \
    0x642cd590, 0x8059, 0x4c0a, {                                              \
      0xa9, 0x58, 0xc5, 0xec, 0x07, 0xd2, 0x3c, 0x4b                           \
    }                                                                          \
  }

#define EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL_GUID                         \
  {                                                                            \
    0x5c198761, 0x16a8, 0x4e69, {                                              \
      0x97, 0x2c, 0x89, 0xd6, 0x79, 0x54, 0xf8, 0x1d                           \
    }                                                                          \
  }

#define EFI_DRIVER_FAMILY_OVERRIDE_PROTOCOL_GUID                               \
  {                                                                            \
    0xb1ee129e, 0xda36, 0x4181, {                                              \
      0x91, 0xf8, 0x04, 0xa4, 0x92, 0x37, 0x66, 0xa7                           \
    }                                                                          \
  }

#define EFI_DRIVER_HEALTH_PROTOCOL_GUID                                        \
  {                                                                            \
    0x2a534210, 0x9280, 0x41d8, {                                              \
      0xae, 0x79, 0xca, 0xda, 0x01, 0xa2, 0xb1, 0x27                           \
    }                                                                          \
  }

#define EFI_ADAPTER_INFORMATION_PROTOCOL_GUID                                  \
  {                                                                            \
    0xe5dd1403, 0xd622, 0xc24E, {                                              \
      0x84, 0x88, 0xc7, 0x1b, 0x17, 0xf5, 0xe8, 0x02                           \
    }                                                                          \
  }

#define EFI_ADAPTER_INFO_MEDIA_STATE_GUID                                      \
  {                                                                            \
    0xd7c74207, 0xa831, 0x4a26 {                                               \
      0xb1, 0xf5, 0xd1, 0x93, 0x06, 0x5c, 0xe8, 0xb6                           \
    }                                                                          \
  }

#define EFI_ADAPTER_INFO_NETWORK_BOOT_GUID                                     \
  {                                                                            \
    0x1fbd2960, 0x4130, 0x41e5, {                                              \
      0x94, 0xac, 0xd2, 0xcf, 0x03, 0x7f, 0xb3, 0x7c                           \
    }                                                                          \
  }

#define EFI_ADAPTER_INFO_SAN_MAC_ADDRESS_GUID                                  \
  {                                                                            \
    0x114da5ef, 0x2cf1, 0x4e12, {                                              \
      0x9b, 0xbb, 0xc4, 0x70, 0xb5, 0x52, 0x05, 0xd9                           \
    }                                                                          \
  }

#define EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT_GUID                                \
  {                                                                            \
    0x4bd56be3, 0x4975, 0x4d8a, {                                              \
      0xa0, 0xad, 0xc4, 0x91, 0x20, 0x4b, 0x5d, 0x4d                           \
    }                                                                          \
  }

#define EFI_ADAPTER_INFO_MEDIA_TYPE_GUID                                       \
  {                                                                            \
    0x8484472f, 0x71ec, 0x411a, {                                              \
      0xb3, 0x9c, 0x62, 0xcd, 0x94, 0xd9, 0x91, 0x6e                           \
    }                                                                          \
  }

#define EFI_ADAPTER_INFO_CDAT_TYPE_GUID                                        \
  {                                                                            \
    0x77af24d1, 0xb6f0, 0x42b9, {                                              \
      0x83, 0xf5, 0x8f, 0xe6, 0xe8, 0x3e, 0xb6, 0xf0                           \
    }                                                                          \
  }

namespace efi {

typedef struct DriverBindingProtocol {
  typedef Status(EFIAPI *IsSupported)(
      IN struct DriverBindingProtocol *instance,
      IN Handle controllerHandle,
      IN DevicePath *remainingDevicePath OPTIONAL
  );

  typedef Status(EFIAPI *Start)(
      IN struct DriverBindingProtocol *instance,
      IN Handle controllerHandle,
      IN DevicePath *remainingDevicePath OPTIONAL
  );

  typedef Status(EFIAPI *Stop)(
      IN struct DriverBindingProtocol *instance,
      IN Handle controllerHandle,
      IN uint64_t numberOfChildren,
      IN Handle *childHandleBuffer OPTIONAL
  );

  IsSupported isSupported;
  Start start;
  Stop stop;

  uint32_t version;
  Handle imageHandle;
  Handle driverBindingHandle;
} DriverBindingProtocol;

typedef struct PlatformDriverOverrideProtocol {
  typedef Status(EFIAPI *GetDriver)(
      IN struct PlatformDriverOverrideProtocol *instance,
      IN Handle controllerHandle,
      IN OUT Handle *driverImageHandle
  );

  typedef Status(EFIAPI *GetDriverPath)(
      IN struct PlatformDriverOverrideProtocol *instance,
      IN Handle controllerHandle,
      IN OUT DevicePath **driverImagePath
  );

  typedef Status(EFIAPI *DriverLoaded)(
      IN struct PlatformDriverOverrideProtocol *instance,
      IN Handle controllerHandle,
      IN DevicePath *driverImagePath,
      IN Handle driverImageHandle
  );

  GetDriver getDriver;
  GetDriverPath getDriverPath;
  DriverLoaded driverLoaded;
} PlatformDriverOverrideProtocol;

typedef struct BusSpecificDriverOverrideProtocol {
  typedef Status(EFIAPI *GetDriver)(
      IN struct BusSpecificDriverOverrideProtocol *instance,
      IN OUT Handle *driverImageHandle
  );

  GetDriver getDriver;
} BusSpecificDriverOverrideProtocol;

typedef struct DriverDiagnostics2Protocol {
  enum class DiagnosticType : uint32_t {
    Standard,
    Extended,
    Manufacturing,
    Cancel
  };

  typedef Status(EFIAPI *RunDiagnostics)(
      IN struct DriverDiagnostics2Protocol *instance,
      IN Handle controllerHandle,
      IN Handle childHandle OPTIONAL,
      IN DiagnosticType type,
      IN char *language,
      OUT Guid **errorType,
      OUT uint64_t *bufferSize,
      OUT char16_t **buffer
  );

  RunDiagnostics runDiagnostics;
  char *supportedLanguages;
} DriverDiagnostics2Protocol;

typedef struct ComponentName2Protocol {
  typedef Status(EFIAPI *GetDriverName)(
      IN struct ComponentName2Protocol *instance,
      IN char *language,
      OUT char16_t **driverName
  );

  typedef Status(EFIAPI *GetControllerName)(
      IN struct ComponentName2Protocol *instance,
      IN Handle controllerHandle,
      IN Handle childHandle OPTIONAL,
      IN char *language,
      OUT char16_t **controllerName
  );

  GetDriverName getDriverName;
  GetControllerName getControllerName;
  char *supportedLanguages;
} ComponentName2Protocol;

typedef struct ServiceBindingProtocol {
  typedef Status(EFIAPI *CreateChild)(
      IN struct ServiceBindingProtocol *instance,
      IN OUT Handle *childHandle
  );

  typedef Status(EFIAPI *DestroyChild)(
      IN struct ServiceBindingProtocol *instance,
      IN Handle childHandle
  );

  CreateChild createChild;
  DestroyChild destroyChild;
} ServiceBindingProtocol;

typedef struct PlatformToDriverConfigurationProtocol {
  enum class PlatformConfigurationAction : uint32_t {
    None,
    StopController,
    RestartController,
    RestartPlatform,
    NvramFailed,
    UnsupportedGuid
  };

  typedef Status(EFIAPI *Query)(
      IN struct PlatformToDriverConfigurationProtocol *instance,
      IN Handle controllerHandle,
      IN Handle childHandle OPTIONAL,
      IN uint64_t *index,
      OUT Guid **parameterTypeGuid,
      OUT void **parameterBlock,
      OUT uint64_t *parameterBlockSize
  );

  typedef Status(EFIAPI *Response)(
      IN struct PlatformToDriverConfigurationProtocol *instance,
      IN Handle controllerHandle,
      IN Handle childHandle OPTIONAL,
      IN uint64_t *index,
      IN Guid *parameterTypeGuid,
      IN void *parameterBlock,
      IN uint64_t parameterBlockSize,
      IN PlatformConfigurationAction action
  );

  Query query;
  Response response;
} PlatformToDriverConfigurationProtocol;

typedef struct {
  uint32_t length;
  uint32_t firmwareVersion;
} DriverSupportedEfiVersionProtocol;

typedef struct DriverFamilyOverrideProtocol {
  typedef uint32_t(EFIAPI *GetVersion)(
      IN struct DriverFamilyOverrideProtocol *instance
  );

  GetVersion getVersion;
} DriverFamilyOverrideProtocol;

typedef struct DriverHealthProtocol {
  enum class HealthStatus : uint32_t {
    Healthy,
    RepairRequired,
    ConfigurationRequired,
    Failed,
    ReconnectRequired,
    RebootRequired
  };

  typedef struct {
    Handle hiiHandle;
    uint16_t stringId;
    uint64_t messageCode;
  } HiiMessage;

  typedef Status(EFIAPI *RepairNotify)(IN uint64_t value, IN uint64_t limit);

  typedef Status(EFIAPI *GetHealthStatus)(
      IN struct DriverHealthProtocol *instance,
      IN Handle controllerHandle,
      IN Handle childHandle OPTIONAL,
      OUT HealthStatus *healthStatus OPTIONAL,
      OUT HiiMessage **messageList,
      OUT Handle *formHiiHandle OPTIONAL
  );

  typedef Status(EFIAPI *Repair)(
      IN struct DriverHealthProtocol *instance,
      IN Handle controllerHandle,
      IN Handle childHandle OPTIONAL,
      IN RepairNotify notify OPTIONAL
  );

  GetHealthStatus getHealthStatus;
  Repair repair;
} DriverHealthProtocol;

typedef struct AdapterInformationProtocol {
  typedef struct {
    Status mediaState;
  } NetworkMediaStateInfo;

  typedef struct {
    uint8_t mediaType;
  } NetworkMediaTypeInfo;

  typedef struct {
    bool iSsciIpv4BootCapablity;
    bool iScsiIpv6BootCapablity;
    bool fCoeBootCapablity;
    bool offloadCapability;
    bool iScsiMpioCapability;
    bool iScsiIpv4Boot;
    bool iScsiIpv6Boot;
    bool fCoeBoot;
  } NetworkBootInfo;

  typedef struct {
    Network::MacAddress sanMacAddress;
  } SanMacAddressInfo;

  typedef struct {
    bool ipv6Support;
  } UndiIpv6SupportInfo;

  typedef struct {
    uint64_t cdatSize;
    uint8_t cdat[];
  } CdatTypeInfo;

  typedef Status(EFIAPI *GetInformation)(
      IN struct AdapterInformationProtocol *instance,
      IN Guid *informationType,
      OUT void **informationBlock,
      OUT uint64_t *informationBlockSize
  );

  typedef Status(EFIAPI *SetInformation)(
      IN struct AdapterInformationProtocol *instance,
      IN Guid *informationType,
      IN void *informationBlock,
      IN uint64_t informationBlockSize
  );

  typedef Status(EFIAPI *GetSupportedTypes)(
      IN struct AdapterInformationProtocol *instance,
      OUT Guid **infoTypesBuffer,
      OUT uint64_t *infoTypesBufferCount
  );

  GetInformation getInformation;
  SetInformation setInformation;
  GetSupportedTypes getSupportedTypes;
} AdapterInformationProtocol;

} // namespace efi